import asyncio
import time
from datetime import datetime, timedelta, timezone
import os

import bleak.exc
from bleak import BleakScanner, BleakClient
import warnings

with warnings.catch_warnings():
    warnings.filterwarnings("ignore")

start_time = int(time.time())
last_save_time = time.time()
latest_time = time.time()
last_realdata = ""
duplicate_count = 0

# 设备的MAC地址
# par_device_addr = "EB:70:FE:51:47:2A"
# par_device_addr = "DB:28:2C:65:9C:28"
par_device_addr = "E1:D4:64:05:E8:0E"
# 接收终端数据的UUID
rece_characteristic_uuid = "0000fff1-0000-1000-8000-00805f9b34fb"
# 向终端发送数据的UUID
send_characteristic_uuid = "0000fff2-0000-1000-8000-00805f9b34fb"

OPEN_SENSOR = bytearray([0x68, 0x02, 0x09, 0x00, 0x01, 0x04, 0x01, 0x08, 0x01, 0x0c, 0x01, 0x22, 0x01, 0xB2, 0x16])

CLOSE_SENSOR = bytearray([0x68, 0x02, 0x09, 0x00, 0x01, 0x04, 0x00, 0x08, 0x00, 0x0c, 0x00, 0x22, 0x00, 0xAE, 0x16])

# 数据全局变量
heart_rate = 0
resting_heart_rate = 0
sleep_state = 0
step_counts = 0
diastolic_blood_pressure = 0
systolic_blood_pressure = 0
blood_oxygen = 0
hrv = 0
beijing_datetime = ""
power = 0
temp = 0.1


def run_watch(q_watch):

    def bytearray_to_hex_string(data):
        return ''.join(['{:02X}'.format(byte) for byte in data])


    async def dealData(data: str):
        global heart_rate, resting_heart_rate, step_counts, sleep_state
        global diastolic_blood_pressure, systolic_blood_pressure, blood_oxygen
        global hrv, beijing_datetime, power, temp
        nonlocal scanner

        heart_rate = int(data[2:4], 16)

        resting_heart_rate = int(data[32:34], 16)

        step_counts = int(str(data[8:10] + data[6:8] + data[4:6]), 16)

        sleep_state = int(data[12:14], 16)

        systolic_blood_pressure = int(data[14:16], 16)

        diastolic_blood_pressure = int(data[16:18], 16)

        blood_oxygen = int(data[18:20], 16)

        hrv = int(data[20:22], 16)

        utc_timestamp = int(str(data[30:32] + data[28:30] + data[26:28] + data[24:26]), 16)
        utc_datetime = datetime.utcfromtimestamp(utc_timestamp).replace(tzinfo=timezone.utc)
        beijing_timezone = timezone(timedelta(hours=0))
        beijing_datetime = utc_datetime.astimezone(beijing_timezone)

        power = int(data[34:36], 16)
        temp_int = int(data[36:38], 16)
        temp_dec = int(data[38:40], 16)
        temp = temp_int + 0.01 * temp_dec

        watch_para = [heart_rate, blood_oxygen, hrv, temp]
        q_watch.put(watch_para)
        # q_watch.put((1, heart_rate))
        # q_watch.put((2, blood_oxygen))
        # q_watch.put((3, hrv))
        # q_watch.put((4, temp))

        cache_str = (f'Heart Rate: {heart_rate, resting_heart_rate} bmp\n' +
                     f'Step Count: {step_counts}\n' + f'Sleep State: {sleep_state}\n' +
                     f'Diastolic Blood Pressure: {diastolic_blood_pressure}\n' +
                     f'Systolic Blood Pressure: {systolic_blood_pressure}\n' +
                     f'Blood Oxygen: {blood_oxygen}\n' + f'HRV: {hrv}\n' +
                     f'Time: {beijing_datetime.strftime("%Y-%m-%d %H:%M:%S")}\n' +
                     f'Power: {power}\n' + f'Temperature: {temp_int}.{temp_dec}\n' +
                     '-------------------------------')
        print(cache_str)


    def getLatestTimeStamp(data: str):
        utc_timestamp = int(str(data[30:32] + data[28:30] + data[26:28] + data[24:26]), 16)
        return utc_timestamp


    async def callback(sender, advertisement_data):
        global last_save_time, latest_time, last_realdata, duplicate_count

        latest_time = 0
        realdata = ""
        if str(sender).find("E1:D4:64:05:E8:0E") != -1:
            ble_data = advertisement_data.manufacturer_data
            # del ble_data[184]
            if time.time() - last_save_time > 1:
                # print(ble_data)
                last_save_time = time.time()
                for k in ble_data:
                    if k == 2230:
                        continue
                    s = str(hex(k))[2:]
                    head_str = s[2:4] + s[0:2]
                    data = head_str + bytearray_to_hex_string(ble_data[k])
                    timestamp = getLatestTimeStamp(data)
                    if timestamp > latest_time:
                        realdata = data
                        latest_time = timestamp

                if realdata == last_realdata:
                    duplicate_count = duplicate_count + 1
                    if duplicate_count > 15:
                        print("Restart Sensor")
                        await scanner.stop()
                        try:
                            await restartSensor()
                        except bleak.exc.BleakDBusError as e:
                            print(e)
                            await restartSensor()
                        await scanner.start()
                else:
                    duplicate_count = 0
                    last_realdata = realdata
                    await dealData(realdata)
                    with open("./data/broadcast_data.txt", 'a') as f:
                        data = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime()) + ": " + realdata + "\n"
                        f.write(data)


    scanner = BleakScanner(detection_callback=callback)


    async def restartSensor():
        device = await BleakScanner.find_device_by_address(
            par_device_addr, cb=dict(use_bdaddr=False)
        )

        async with BleakClient(device) as client:
            client.connect()
            client.connect()

            await client.write_gatt_char(send_characteristic_uuid, OPEN_SENSOR)
            await asyncio.sleep(2.0)
            await client.write_gatt_char(send_characteristic_uuid, CLOSE_SENSOR)
            await asyncio.sleep(2.0)
            await client.disconnect()

        async with BleakClient(device) as client:
            client.connect()
            client.connect()

            await client.write_gatt_char(send_characteristic_uuid, OPEN_SENSOR)
            await asyncio.sleep(1.0)
            await client.disconnect()
        print("Sensor Working")


    async def main():
        nonlocal scanner
        folder = os.path.exists("./data")

        if not folder:
            os.makedirs("./data")

        try:
            await restartSensor()
        except bleak.exc.BleakDBusError as e:
            print(e)
            await restartSensor()

        disconnected_event = asyncio.Event()
        await scanner.start()
        # await asyncio.sleep(28800)
        await disconnected_event.wait()
        await scanner.stop()


    asyncio.run(main())
